#include "Player.hh"
#include "Galaxy.hh"
#include "User.hh"
#include "../Exception.hh"

using namespace Geom;
using namespace World;

spPlayer Player::construct(spGalaxy galaxy, spUser user) {
    spPlayer player = spPlayer(new Player(galaxy, user));
    return player;
}

Player::Player(spGalaxy galaxy, spUser user):
    lock(QMutex::Recursive),
    galaxy(galaxy),
    user(user),
    fleetId(0),
    money(0) {}

spPlayer Player::self() const {
    spGalaxy _galaxy = galaxy.toStrongRef();
    spUser _user = user.toStrongRef();

    if (_galaxy.isNull())
        throw NullPointerException("Player::self galaxy");

    if (_user.isNull())
        throw NullPointerException("Player::self user");

    spPlayer player = _galaxy->get_player(_user.data());

    if (player.isNull())
        throw NullPointerException("Player::self player");

    return player;
}

void Player::next_turn() {
    QMutexLocker locker(&lock);

    for (
      FleetMap::iterator fleet = fleets.begin();
      fleet != fleets.end();
      ++fleet
    ) {
        (*fleet)->next_turn();
    }
}

/**
 * \brief Pénz elköltése/növelése.
 * \param amount      Ennyi pénzt szeretnénk elkölteni. Negatív, ha növelni
 *                    akarjuk.
 * \param allRequired Minden pénzre szükség van-e. Ha igen és nincs elég, akkor
 *                    nem költ semmit.
 * \return Ennyi pénzt sikerült elkölteni. Lehet kevesebb, mint az igényelt
 *         mennyiség, ha nem volt elég pénze a játékosnak. Növelni mindig a
 *         teljes megadott mennyiséggel lehet.
 */
i8 Player::transaction(i8 amount, bool allRequired) {
    QMutexLocker locker(&lock);

    if (i8(money) - amount < 0)
        amount = allRequired ? 0 : money;

    money -= amount;
    return amount;
}

spFleet Player::get_fleet(FleetMap::key_type id) const {
    QMutexLocker locker(&lock);

    FleetMap::const_iterator iter = fleets.find(id);

    if (iter == fleets.end())
        throw FleetNotFound(id);

    spFleet result = fleets.value(id);
    return result;
}

spFleet Player::add_fleet(
  Vector<> const& position,
  u8 battleship,
  u8 fighter,
  u8 transportship,
  u8 colonyship,
  u8 tank
) {
    QMutexLocker locker(&lock);
    FleetMap::key_type const id = fleetId++;
    spFleet fleet = Fleet::construct(
      id, self(), position, battleship, fighter, transportship, colonyship, tank
    );
    fleets.insert(id, fleet);
    return fleet;
}

void Player::del_fleet(FleetMap::key_type id) {
    QMutexLocker locker(&lock);
    fleets.remove(id);
}

spFleet Player::get_closest_fleet(Vector<> const& position, f8 limit) const {
    QMutexLocker locker(&lock);
    spFleet closest;
    f8 minDist;

    for (
      FleetMap::const_iterator fleet = fleets.begin();
      fleet != fleets.end();
      ++fleet
    ) {
        f8 dist = ((*fleet)->get_position() - position).get_length();

        if (dist < minDist || closest.isNull()) {
            minDist = dist;
            closest = *fleet;
        }
    }

    return (minDist < limit) ? closest : spFleet();
}

QString Player::get_name() const {
    return get_user()->name;
}

WP_GETTER  (Player, Galaxy,   galaxy)
WP_GETTER  (Player, User,     user)
SYNC_GETTER(Player, FleetMap, fleets)
SYNC_GETTER(Player, u8,       money)
